package com.angle3d.samples;

import android.content.Context;
import android.graphics.Bitmap;

import com.angle3d.Mesh;
import com.angle3d.Node;
import com.angle3d.ShaderProgram;
import com.angle3d.ShaderSource;
import com.angle3d.ShaderSource.ShaderType;
import com.angle3d.Texture;
import com.angle3d.VertexBuffer;
import com.angle3d.VertexBuffer.VertexAttribute;

class SceneFactory {
	
	private final static String VertexShaderSource = 
		"precision highp float;" +
		"uniform mat4 ModelView;" +
		"uniform mat4 Projection;" +
		"attribute vec4 Position;" +
        "attribute vec2 TexCoord;" +
        "varying vec2 tcoord;" +
        "void main() {" +
        "tcoord = TexCoord;" + 
        "gl_Position = Projection * ModelView * Position; }";
    
    private final static String FragmentShaderSource = 
        "precision mediump float;" +
        "uniform sampler2D Texture0;" +
        "varying vec2 tcoord;" +
        "void main() {" +
        "vec4 texColor0 = texture2D(Texture0, tcoord);" +
        "gl_FragColor = texColor0 * vec4(1.0, 0.5, 0.0, 1.0); }";
    
    private Mesh createSimpleQuad() {
    	//create a mesh representing a quad
    	//a quad is composed of two triangles
    	Mesh mesh = new Mesh();
    	
    	//create a VertexBuffer with 6 indices, 4 vertices and, for each vertex, two vertex attributes (position and texture coordinates)
    	//The name of the attributes ("Position" and "TexCoord") must match with the ones declared in the vertex shader source code.
    	//The "Position" attribute has 3 components (x, y, z), as the "Position" shader attribute is a vec3.
    	//The "TexCoord" attribute has 2 components (x, y), as the "TexCoord" shader attribute is a vec2.
    	//Check shader code above.
    	VertexBuffer vb = new VertexBuffer(6, 4, new VertexAttribute("Position", 3), new VertexAttribute("TexCoord", 2));
    	
    	//create an array of indices for the two triangles of the quad
    	short[] quadIndices = new short[] { 
    			0, 1, 2, //first triangle (first half of the quad)
    			2, 3, 0, //second triangle (second half of the quad)
    	};
    	
    	//create the quad vertices
    	float[] quadVertices = new float[] {
    		-0.5f, -1.0f, 0.0f, //position coordinates of first vertex
    		 0.0f,  0.0f,       //texture coordinates of first vertex
             0.5f, -1.0f, 0.0f, //position coordinates of second vertex
    		 1.0f,  0.0f,       //texture coordinates of second vertex
    		 0.5f,  0.0f, 0.0f, //position coordinates of third vertex
    		 1.0f,  1.0f,       //texture coordinates of third vertex
    		-0.5f,  0.0f, 0.0f, //position coordinates of fourth vertex
    		 0.0f,  1.0f,       //texture coordinates of fourth vertex         
    	};
    	
    	//set indices and vertices in the vertex buffer
    	vb.setIndices(quadIndices);
    	vb.setVertices(quadVertices);
    	
    	//specify vertex buffer for the mesh
    	mesh.setVertexBuffer(vb);
    	
    	//set the primitive type
    	mesh.setPrimitive(Mesh.Primitive.TRIANGLES);
    	
    	return mesh;
    }
    
    private Mesh createSimpleTriangle() {
    	//create a mesh representing a triangle
    	Mesh mesh = new Mesh();
    	
    	//create a VertexBuffer with 3 indices, 3 vertices and, for each vertex, two vertex attributes (position and texture coordinates)
    	//The name of the attributes ("Position" and "TexCoord") must match with the ones declared in the vertex shader source code.
    	//The "Position" attribute has 3 components (x, y, z), as the "Position" shader attribute is a vec3.
    	//The "TexCoord" attribute has 2 components (x, y), as the "TexCoord" shader attribute is a vec2.
    	//Check shader code above.
    	VertexBuffer vb = new VertexBuffer(3, 3, new VertexAttribute("Position", 3), new VertexAttribute("TexCoord", 2));
    	
    	//create an array of indices for the triangle
    	short[] triangleIndices = new short[] { 
    			0, 1, 2,
    	};
    	
    	//create the triangle vertices
    	float[] triangleVertices = new float[] {
    		-0.5f,  0.0f, 0.0f, //position coordinates of first vertex
    		 0.0f,  0.0f,       //texture coordinates of first vertex
             0.5f,  0.0f, 0.0f, //position coordinates of second vertex
    		 1.0f,  0.0f,       //texture coordinates of second vertex
    		 0.5f,  1.0f, 0.0f, //position coordinates of third vertex
    		 1.0f,  1.0f,       //texture coordinates of third vertex         
    	};
    	
    	//set indices and vertices in the vertex buffer
    	vb.setIndices(triangleIndices);
    	vb.setVertices(triangleVertices);
    	
    	//specify vertex buffer for the mesh
    	mesh.setVertexBuffer(vb);
    	
    	//set the primitive type
    	mesh.setPrimitive(Mesh.Primitive.TRIANGLES);
    	
    	return mesh;
    }
    
    private Mesh createTexturedMesh(Mesh mesh, Context context) {
    	//create the vertex and fragment shaders to render our mesh
		ShaderSource vertex = new ShaderSource(VertexShaderSource, ShaderType.VERTEX);
        ShaderSource fragment = new ShaderSource(FragmentShaderSource, ShaderType.FRAGMENT);
        
        //specify the shader program for rendering the mesh
        mesh.setShaderProgram(new ShaderProgram(vertex, fragment));
        
        //create a texture to be applied on the mesh surface
        Texture texture = new Texture();
        Bitmap bm = SampleUtil.loadBitmap(R.drawable.brick, context);
        texture.setBitmap(bm);
        
        //set the texture in the mesh
        //note that the name "Texture0" must match the texture name in the Vertex shader source code
        mesh.setTexture(texture, "Texture0", 0);
        
    	return mesh;
    }
    
	public Node createScene(Context context) {
		//create the scene root node
		Node scene = new Node();
        
		//create a textured quad mesh
		Mesh mesh1 = createTexturedMesh(createSimpleQuad(), context);
		
		//create a textured triangle mesh
		Mesh mesh2 = createTexturedMesh(createSimpleTriangle(), context);
				
        //create a node to host our mesh
        Node node = new Node();
        
        //attach the meshes to the node
        node.addSceneObject(mesh1);
        node.addSceneObject(mesh2);
        
        //attach our mesh node as child of the scene root
        scene.addChild(node);
        
        //return our scene
        return scene;
	}
}
